package com.swak.persistence;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import com.swak.utils.StringUtils;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * 选择性的更新： 有 Selective 的效果
 * 
 * @author lifeng
 */
@Getter
@Setter
@Accessors(chain = true)
public class Updative extends QueryCondition implements Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * 修改的列
	 */
	private List<UpdativeColumn> columns;

	/**
	 * 乐观锁
	 */
	private Integer version;

	/**
	 * 模型数据
	 */
	private Object model;

	/**
	 * 设置 column to null
	 * 
	 * @param column
	 * @return
	 */
	public Updative update(Object column) {
		if (column == null) {
			throw new RuntimeException("Column cannot be null");
		}
		if (columns == null) {
			columns = new ArrayList<UpdativeColumn>();
		}
		columns.add(UpdativeColumn.of(column));
		return this;
	}

	/**
	 * 设置 column to value
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public Updative update(Object column, Object value) {
		if (column == null) {
			throw new RuntimeException("Column cannot be null");
		}
		if (columns == null) {
			columns = new ArrayList<UpdativeColumn>();
		}
		columns.add(UpdativeColumn.of(column, value));
		return this;
	}

	/**
	 * 校验Updative的有效性
	 * 
	 * @return
	 */
	public boolean isUpdativeValid() {
		return columns != null && columns.size() > 0 && (super.isValid() || this.model != null);
	}

	public Updative andIsNull(String column) {
		if (StringUtils.isNotBlank(column)) {
			getCriteria().andIsNull(column);
		}
		return this;
	}

	public Updative andIsNotNull(String column) {
		if (StringUtils.isNotBlank(column)) {
			getCriteria().andIsNotNull(column);
		}
		return this;
	}

	public Updative andConditionSql(String conditionSql) {
		if (StringUtils.isNotBlank(conditionSql)) {
			getCriteria().andConditionSql(conditionSql);
		}
		return this;
	}

	public Updative andEqualTo(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andEqualTo(column, value);
		}
		return this;
	}

	public Updative andNotEqualTo(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andNotEqualTo(column, value);
		}
		return this;
	}

	public Updative andGreaterThan(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andGreaterThan(column, value);
		}
		return this;
	}

	public Updative andGreaterThanOrEqualTo(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andGreaterThanOrEqualTo(column, value);
		}
		return this;
	}

	public Updative andLessThan(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andLessThan(column, value);
		}
		return this;
	}

	public Updative andLessThanOrEqualTo(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andLessThanOrEqualTo(column, value);
		}
		return this;
	}

	public Updative andIn(String column, List<?> values) {
		if (StringUtils.isNotBlank(column) && values != null) {
			this.getCriteria().andIn(column, values);
		}
		return this;
	}

	public Updative andNotIn(String column, List<?> values) {
		if (StringUtils.isNotBlank(column) && values != null) {
			this.getCriteria().andNotIn(column, values);
		}
		return this;
	}

	public Updative andBetween(String column, Object value1, Object value2) {
		if (StringUtils.isNotBlank(column) && value1 != null && value2 != null) {
			this.getCriteria().andBetween(column, value1, value2);
		}
		return this;
	}

	public Updative andNotBetween(String column, Object value1, Object value2) {
		if (StringUtils.isNotBlank(column) && value1 != null && value2 != null) {
			this.getCriteria().andBetween(column, value1, value2);
		}
		return this;
	}

	public Updative andLike(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andLike(column, value);
		}
		return this;
	}

	public Updative andLeftLike(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andLeftLike(column, value);
		}
		return this;
	}

	public Updative andRightLike(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andRightLike(column, value);
		}
		return this;
	}

	public Updative andNotLike(String column, Object value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andNotLike(column, value);
		}
		return this;
	}

	public Updative andDateEqualTo(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateEqualTo(column, value);
		}
		return this;
	}

	public Updative andDateNotEqualTo(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateNotEqualTo(column, value);
		}
		return this;
	}

	public Updative andDateGreaterThan(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateGreaterThan(column, value);
		}
		return this;
	}

	public Updative andDateGreaterThanOrEqualTo(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateGreaterThanOrEqualTo(column, value);
		}
		return this;
	}

	public Updative andDateLessThan(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateLessThan(column, value);
		}
		return this;
	}

	public Updative andDateLessThanOrEqualTo(String column, LocalDateTime value) {
		if (StringUtils.isNotBlank(column) && value != null) {
			this.getCriteria().andDateLessThanOrEqualTo(column, value);
		}
		return this;
	}

	public Updative andDateIn(String column, List<LocalDateTime> values) {
		if (StringUtils.isNotBlank(column) && values != null) {
			this.getCriteria().andDateIn(column, values);
		}
		return this;
	}

	public Updative andDateNotIn(String column, List<LocalDateTime> values) {
		if (StringUtils.isNotBlank(column) && values != null) {
			this.getCriteria().andDateNotIn(column, values);
		}
		return this;
	}

	public Updative andDateBetween(String column, LocalDateTime value1, LocalDateTime value2) {
		if (StringUtils.isNotBlank(column) && value1 != null && value2 != null) {
			this.getCriteria().andDateBetween(column, value1, value2);
		}
		return this;
	}

	public Updative andDateNotBetween(String column, LocalDateTime value1, LocalDateTime value2) {
		if (StringUtils.isNotBlank(column) && value1 != null && value2 != null) {
			this.getCriteria().andDateNotBetween(column, value1, value2);
		}
		return this;
	}

	protected Updative selecteBy(Selective selective) {
		if (selective != null) {
			this.criteria = selective.criteria;
			this.orCriterias = selective.orCriterias;
		}
		return this;
	}

	protected Updative selecteBy(Object model) {
		this.model = model;
		return this;
	}

	public static Updative of() {
		return new Updative();
	}

	@Data
	public static class UpdativeColumn implements Serializable {
		private static final long serialVersionUID = 1L;

		private Object column;
		private Object value;

		public static UpdativeColumn of(Object column) {
			UpdativeColumn updativeColumn = new UpdativeColumn();
			updativeColumn.column = column;
			updativeColumn.value = null;
			return updativeColumn;
		}

		public static UpdativeColumn of(Object column, Object value) {
			UpdativeColumn updativeColumn = new UpdativeColumn();
			updativeColumn.column = column;
			updativeColumn.value = QueryCondition.escape(value);
			return updativeColumn;
		}
	}
}